package com.iot08.admin.utils;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0
 * @Description: 支付宝支付工具类
 * @author: Rock
 * @time: 2021/2/27 11:31
 */
@Slf4j
@Component
public class AlipayUtil {

    @Value("${alipay.appid}")
    private String alipayAppid;

    @Value("${alipay.gateway.url}")
    private String alipayGatewayUrl;

    @Value("${alipay.public.key}")
    private String alipayPublicKey;

    @Value("${alipay.private.key}")
    private String alipayPrivateKey;

    // 字符编码格式
    private static final String CHARSET = "utf-8";

    // 数据格式
    private static final String FORMAT = "json";

    // 销售产品码，商家和支付宝签约的产品码
    //private static final String PRODUCT_CODE = "QUICK_MSECURITY_PAY";
    private static final String PRODUCT_CODE = "QUICK_WAP_PAY";

    // 签名方式
    private static final String SIGN_TYPE = "RSA2";

    // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
    private static final String TIME_EXPIRE = "30m";

    /**
     * 生成APP支付订单签名信息
     *
     * @param subject     商品的标题/交易标题/订单标题/订单关键字等
     * @param body        对一笔交易的具体描述信息。如果是多种商品，请将商品描述字符串累加传给body
     * @param totalAmount 订单总金额，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
     * @param outTradeNo  商户网站唯一订单号
     * @param notifyUrl   商户网站接收支付宝异步回调地址
     * @return
     * @throws AlipayApiException
     * @author:Rock
     * @time:2021-2-27 11:38:58
     */
    private AlipayTradeAppPayResponse createSignData(String subject, String body, String totalAmount, String outTradeNo, String notifyUrl) throws AlipayApiException {
        // 实例化客户端
        AlipayClient alipayClient = buildAlipayClient();
        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)
        AlipayTradeAppPayModel bizModel = new AlipayTradeAppPayModel();
        // 商品的标题/交易标题/订单标题/订单关键字等。
        bizModel.setSubject(subject);
        // 对一笔交易的具体描述信息。如果是多种商品，请将商品描述字符串累加传给body。
        bizModel.setBody(body);
        // 商户网站唯一订单号
        bizModel.setOutTradeNo(outTradeNo);
        // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
        bizModel.setTimeoutExpress(TIME_EXPIRE);
        // 订单总金额，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
        bizModel.setTotalAmount(totalAmount);
        // 销售产品码，商家和支付宝签约的产品码
        bizModel.setProductCode(PRODUCT_CODE);
        request.setBizModel(bizModel);
        // 商户网站接收支付宝异步回调地址
        request.setNotifyUrl(notifyUrl);
        //支付请求
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        log.info("支付宝支付订单生成信息：{}",response);
        //调用成功，则处理业务逻辑
        return response;
    }


    /**
     * @description 退款申请
     * @author cwj
     * @param [tradeNo, outTradeNo, refundAmount, refundReason, outRequestNo, notifyUrl]
     * @return com.alipay.api.response.AlipayTradeRefundResponse
     * @date @time 2025/2/6 16:42
     **/
    public AlipayTradeRefundResponse refundApply(String tradeNo, String outTradeNo, String refundAmount, String refundReason, String outRequestNo,String notifyUrl) throws AlipayApiException {
        // 构造请求参数以调用接口
        AlipayClient alipayClient = buildAlipayClient();
        // 构造请求参数以调用接口
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        // 设置商户订单号
        model.setOutTradeNo(outTradeNo);
        // 设置支付宝交易号
        model.setTradeNo(tradeNo);
        // 设置退款金额
        model.setRefundAmount(refundAmount);
        // 设置退款原因说明
        model.setRefundReason(refundReason);
        // 设置退款请求号
        model.setOutRequestNo(outRequestNo);
        // 设置查询选项
        List<String> queryOptions = new ArrayList<>();
        queryOptions.add("refund_detail_item_list");
        model.setQueryOptions(queryOptions);
        request.setBizModel(model);
        //设置退款通知url
        request.setNotifyUrl(notifyUrl);
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        log.info("支付宝退款申请的返回结果：{}",response.getBody());
        return response;
    }


    /**
     * @description 查询退款申请的信息
     * @author cwj
     * @param [outRequestNo, tradeNo, outTradeNo]
     * @return com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse
     * @date @time 2025/2/10 17:14
     **/
    public AlipayTradeFastpayRefundQueryResponse queryRefundInfo(String outRequestNo,String tradeNo, String outTradeNo) throws AlipayApiException {
        //构造请求参数以调用接口
        AlipayClient alipayClient = buildAlipayClient();
        //构建查询请求对象
        AlipayTradeFastpayRefundQueryRequest request = buildAlipayTradeFastpayRefundQueryRequest(outRequestNo, tradeNo, outTradeNo);
        //执行查询
        AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
        log.info("查询退款信息的内容为：{}",response);
        return response;

    }

    /**
     * @description 构建请求
     * @author cwj
     * @param [outRequestNo, tradeNo, outTradeNo]
     * @return com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest
     * @date @time 2025/2/10 17:13
     **/
    private AlipayTradeFastpayRefundQueryRequest buildAlipayTradeFastpayRefundQueryRequest(String outRequestNo, String tradeNo, String outTradeNo) {
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        //设置退款请求号
        model.setOutRequestNo(outRequestNo);
        // 设置支付宝交易号
        model.setTradeNo(tradeNo);
        // 设置商户订单号
        model.setOutTradeNo(outTradeNo);
        // 设置查询选项
        List<String> queryOptions = new ArrayList<>();
        queryOptions.add("refund_detail_item_list");
        model.setQueryOptions(queryOptions);
        request.setBizModel(model);
        return request;
    }


    /**
     * @description 构建支付宝客服端连接对象
     * @author cwj
     * @param []
     * @return com.alipay.api.AlipayClient
     * @date @time 2025/2/6 15:02
     **/
    private AlipayClient buildAlipayClient() {
        return new DefaultAlipayClient(alipayGatewayUrl, alipayAppid, alipayPrivateKey, FORMAT, CHARSET, alipayPublicKey, SIGN_TYPE);
    }

    /**
     * 生成APP支付订单签名信息字符串
     *
     * @param subject     商品的标题/交易标题/订单标题/订单关键字等
     * @param body        对一笔交易的具体描述信息。如果是多种商品，请将商品描述字符串累加传给body
     * @param totalAmount 订单总金额，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
     * @param outTradeNo  商户网站唯一订单号
     * @param notifyUrl   商户网站接收支付宝异步回调地址
     * @return
     * @throws AlipayApiException
     * @author:Rock
     * @time: 2021-2-27 17:25:55
     */
    public String createSignDataStr(String subject, String body, String totalAmount, String outTradeNo, String notifyUrl) throws AlipayApiException {
        AlipayTradeAppPayResponse response = createSignData(subject, body, totalAmount, outTradeNo, notifyUrl);
        if (null != response && response.isSuccess()) {
            log.info("支付宝统一下单返回参数内容：{}",response.getBody());
            return response.getBody();
        }
        return null;
    }

    /**
     * 验证异步通知信息参数
     *
     * @param params
     * @time: 2021/2/27 17:25
     * @author: Rock
     * @version 1.0
     */
    public boolean notifyParamSignVerify(Map<String, String> params) throws AlipayApiException {
        return AlipaySignature.rsaCheckV1(params, alipayPublicKey, CHARSET, params.get("sign_type"));
    }


    /**
     * @description 查询支付宝支付订单信息
     * @author cwj
     * @param [outTradeNo, tradeNo]
     * @return java.lang.String
     * @date @time 2025/1/7 16:56
     **/
    public AlipayTradeQueryResponse queryPaymentOrderInfo(String outTradeNo,String tradeNo) throws AlipayApiException {
        // 实例化客户端
        AlipayClient alipayClient = buildAlipayClient();
        // 构造请求参数以调用接口，实例化alipay.trade.query接口
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        if(StringUtils.isNotEmpty(outTradeNo)){
            model.setOutTradeNo(outTradeNo);
        }
        if(StringUtils.isNotEmpty(tradeNo)){
            model.setTradeNo(tradeNo);
        }
        request.setBizModel(model);
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        log.info("查询支付宝订单的内容为{}",response);
        return response;
    }

}
